package net.simflow.swf.analyzer.fileprinter;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.TreeMap;

import net.simflow.swf.analyzer.exec.data.ExecResult;
import net.simflow.swf.analyzer.exec.data.TaskExecResult;
import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Service;

public class ExecResultFilePrinter {
	private static final LinkedHashMap<String, Boolean> DEFAULT_CONFIG = new LinkedHashMap<String, Boolean>();
	static {
		DEFAULT_CONFIG.put(ExecResult.ORIGINAL_EXECUTION_RESULT, true);
		DEFAULT_CONFIG.put(ExecResult.TOTAL_STEP, true);
		DEFAULT_CONFIG.put(ExecResult.FLOW_CREATION_SPEED, true);
		DEFAULT_CONFIG.put(ExecResult.SERVICE_SCHEDULE, true);
		DEFAULT_CONFIG.put(ExecResult.SERVICE_ABILITY, true);
		DEFAULT_CONFIG.put(ExecResult.FLOW_RELDEADLINE, true);
		DEFAULT_CONFIG.put(ExecResult.FLOW_WEIGHT, true);
	}

	private static ExecResultFilePrinter instance = new ExecResultFilePrinter();

	private ExecResultFilePrinter() {
	}

	public static ExecResultFilePrinter getInstance() {
		return instance;
	}

	public void print(FilePrinter p, ExecResult execResult) {
		if (p == null) {
			return;
		}
		if (execResult == null) {
			return;
		}

		int totalStep = execResult.getTotalStep();
		double flowCreateSpeed = execResult.getFlowCreateSpeed();
		HashMap<Service, Integer> serviceAbilityMap = execResult
				.getServiceAbilityMap();
		HashMap<Service, Integer> serviceScheduleMap = execResult
				.getServiceScheduleMap();
		HashMap<Flow, Integer> flowRelDeadlineMap = execResult
				.getFlowRelDeadlineMap();
		HashMap<Flow, Integer> flowWeightMap = execResult.getFlowWeightMap();
		TreeMap<Integer, TaskExecResult> taskExecMap = execResult
				.getTaskExecMap();

		p.print(FilePrinter.NEW_LINE + "Execution Info:");
		for (Entry<String, Boolean> en : DEFAULT_CONFIG.entrySet()) {
			if (!en.getValue()) {
				continue;
			}

			String title = en.getKey();
			switch (title) {
			case ExecResult.ORIGINAL_EXECUTION_RESULT:
				if (taskExecMap != null) {
					int totalCount = 0;
					int successCount = 0;
					int unfinishedCount = 0;
					totalCount = taskExecMap.size();
					for (Entry<Integer, TaskExecResult> en1 : taskExecMap
							.entrySet()) {
						if (en1.getValue().getEndTime() == -1) {
							unfinishedCount++;
						} else {
							successCount++;
						}
					}

					boolean is = true;
					taskExecMap.comparator();
					for (Entry<Integer, TaskExecResult> en1 : taskExecMap
							.entrySet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ": Total "
									+ totalCount + ": Succeess " + successCount
									+ ": Unfinish " + unfinishedCount);
							is = false;
						}
						p.print(FilePrinter.TAB + en1.getValue().getInfo());
					}
				}
				break;
			case ExecResult.FLOW_CREATION_SPEED:
				p.print(FilePrinter.NEW_LINE + title + ":" + FilePrinter.TAB
						+ flowCreateSpeed);
				break;
			case ExecResult.TOTAL_STEP:
				p.print(FilePrinter.NEW_LINE + title + ":" + FilePrinter.TAB
						+ totalStep);
				break;
			case ExecResult.SERVICE_SCHEDULE:
				if (serviceScheduleMap != null) {
					boolean is = true;
					for (Entry<Service, Integer> en1 : serviceScheduleMap
							.entrySet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ":");
							is = false;
						}
						p.print(FilePrinter.TAB
								+ en1.getKey().getNameInNetwork() + ": "
								+ en1.getValue());
					}
				}
				break;
			case ExecResult.SERVICE_ABILITY:
				if (serviceAbilityMap != null) {
					boolean is = true;
					for (Entry<Service, Integer> en1 : serviceAbilityMap
							.entrySet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ":");
							is = false;
						}
						p.print(FilePrinter.TAB
								+ en1.getKey().getNameInNetwork() + ": "
								+ en1.getValue());
					}
				}
				break;
			case ExecResult.FLOW_RELDEADLINE:
				if (flowRelDeadlineMap != null) {
					boolean is = true;
					for (Entry<Flow, Integer> en1 : flowRelDeadlineMap
							.entrySet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ":");
							is = false;
						}
						p.print(FilePrinter.TAB
								+ en1.getKey().getNameInNetwork() + ": "
								+ en1.getValue());
					}
				}
				break;
			case ExecResult.FLOW_WEIGHT:
				if (flowWeightMap != null) {
					boolean is = true;
					for (Entry<Flow, Integer> en1 : flowWeightMap.entrySet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ":");
							is = false;
						}
						p.print(FilePrinter.TAB
								+ en1.getKey().getNameInNetwork() + ": "
								+ en1.getValue());
					}
				}
				break;
			}
		}
	}

	public void print(FilePrinter p, ExecResult execResult, Flow flow) {
		if (p == null) {
			return;
		}
		if (execResult == null) {
			return;
		}

		int totalStep = execResult.getTotalStep();
		double flowCreateSpeed = execResult.getFlowCreateSpeed();
		HashMap<Service, Integer> serviceScheduleMap = execResult
				.getServiceScheduleMap();
		HashMap<Service, Integer> serviceAbilityMap = execResult
				.getServiceAbilityMap();
		HashMap<Flow, Integer> flowRelDeadlineMap = execResult
				.getFlowRelDeadlineMap();
		HashMap<Flow, Integer> flowWeightMap = execResult.getFlowWeightMap();
		TreeMap<Integer, TaskExecResult> taskExecMap = execResult
				.getTaskExecMap();

		p.print(FilePrinter.NEW_LINE + "Execution Info:");
		for (Entry<String, Boolean> en : DEFAULT_CONFIG.entrySet()) {
			if (!en.getValue()) {
				continue;
			}

			String title = en.getKey();
			switch (title) {
			case ExecResult.ORIGINAL_EXECUTION_RESULT:
				if (taskExecMap != null) {
					int totalCount = 0;
					int successCount = 0;
					int unfinishedCount = 0;
					for (Entry<Integer, TaskExecResult> en1 : taskExecMap
							.entrySet()) {
						TaskExecResult res = en1.getValue();
						if (res.getFlow() == flow) {
							totalCount++;
							if (en1.getValue().getEndTime() == -1) {
								unfinishedCount++;
							} else {
								successCount++;
							}
						}
					}

					boolean is = true;
					taskExecMap.comparator();
					for (Entry<Integer, TaskExecResult> en1 : taskExecMap
							.entrySet()) {
						TaskExecResult res = en1.getValue();
						if (res.getFlow() == flow) {
							if (is) {
								p.print(FilePrinter.NEW_LINE + title
										+ ": Total " + totalCount
										+ ": Succeess " + successCount
										+ ": Unfinish " + unfinishedCount);
								is = false;
							}
							p.print(FilePrinter.TAB + res.getInfo());
						}
					}
				}
				break;
			case ExecResult.FLOW_CREATION_SPEED:
				p.print(FilePrinter.NEW_LINE + title + ":" + FilePrinter.TAB
						+ flowCreateSpeed);
				break;
			case ExecResult.TOTAL_STEP:
				p.print(FilePrinter.NEW_LINE + title + ":" + FilePrinter.TAB
						+ totalStep);
				break;
			case ExecResult.SERVICE_SCHEDULE:
				if (serviceScheduleMap != null) {
					boolean is = true;
					for (Service svc : flow.getServiceSet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ":");
							is = false;
						}
						p.print(FilePrinter.TAB + svc.getNameInNetwork() + ": "
								+ serviceScheduleMap.get(svc));
					}
				}
				break;
			case ExecResult.SERVICE_ABILITY:
				if (serviceAbilityMap != null) {
					boolean is = true;
					for (Service svc : flow.getServiceSet()) {
						if (is) {
							p.print(FilePrinter.NEW_LINE + title + ":");
							is = false;
						}
						p.print(FilePrinter.TAB + svc.getNameInNetwork() + ": "
								+ serviceAbilityMap.get(svc));
					}
				}
				break;
			case ExecResult.FLOW_RELDEADLINE:
				if (flowRelDeadlineMap != null
						&& flowRelDeadlineMap.containsKey(flow)) {
					p.print(FilePrinter.NEW_LINE + title + ":"
							+ FilePrinter.TAB + flow.getNameInNetwork() + ": "
							+ flowRelDeadlineMap.get(flow));
				}
				break;
			case ExecResult.FLOW_WEIGHT:
				if (flowWeightMap != null && flowWeightMap.containsKey(flow)) {
					p.print(FilePrinter.NEW_LINE + title + ":"
							+ FilePrinter.TAB + flow.getNameInNetwork() + ": "
							+ flowWeightMap.get(flow));
				}
				break;
			}
		}
	}
}
